/*
 * MagNumTestCase.cpp
 *
 *  Created on: Apr 18, 2011
 *      Author: rego
 */

#include "MagNumTestCase.h"
#include "../src/MagNum.h"
#include "../src/Over100Listener.h"
#include "../src/CriticalPrecisionListener.h"
#include "../src/Mandelbrot.h"

#include <cstdlib>
#include <cstring>
#include <cmath>
#include <memory>

void MagNumTestCase::setUp() {
	mpfr_set_default_prec(MagNum::INITIAL_PRECISION);
}

void MagNumTestCase::testInitialization()
{
	// given

	MagNum m;

	// when

	long actual = m.getInt();

	// then

	CPPUNIT_ASSERT_EQUAL_MESSAGE("It should be 0", 0l, actual);
}

void MagNumTestCase::testInitializationWithChars()
{
	MagNum m;
}

void MagNumTestCase::testInitializationWithDouble()
{
	MagNum m;
}

void MagNumTestCase::testInitializationWithInt()
{
	MagNum m;
}

void MagNumTestCase::testGettingInt()
{
	// given
	long expected = 3444;
	MagNum m(expected);

	// when
	long actual = m.getInt();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("getInt() works wrong, should be 3444", expected, actual);
}

void MagNumTestCase::testGettingIntNegative()
{
	// given
	long expected = -3444;
	MagNum m(expected);

	// when
	long actual = m.getInt();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("getInt() works wrong with negative number, should be -3444", expected, actual);
}

void MagNumTestCase::testGettingIntFromPositiveDecimalRoundingDown()
{
	// given
	double given = 34.44;
	long expected = 34;
	MagNum m(given);

	// when
	long actual = m.getInt();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("getInt() works wrong when number is decimal, should be 34", expected, actual);
}

void MagNumTestCase::testGettingIntFromPositiveDecimalRoundingUp()
{
	// given
	double given = 34.500001;
	long expected = 35;
	MagNum m(given);

	// when
	long actual = m.getInt();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("getInt() works wrong when number is decimal, should be 35", expected, actual);
}

void MagNumTestCase::testGettingIntFromNegativeDecimalRoundingDown()
{
	// given
	double given = -34.44;
	long expected = -34;
	MagNum m(given);

	// when
	long actual = m.getInt();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("getInt() works wrong when number is decimal, should be -34", expected, actual);
}

void MagNumTestCase::testGettingIntFromNegativeDecimalRoundingUp()
{
	// given
	double given = -34.500001;
	long expected = -35;
	MagNum m(given);

	// when
	long actual = m.getInt();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("getInt() works wrong when number is decimal, should be -35", expected, actual);
}

void MagNumTestCase::testGettingDouble()
{
	// given
	double expected = -34.500001;
	MagNum m(expected);

	// when
	double actual = m.getDouble();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("getDouble() works wrong, should be -34.500001", expected, actual);
}

void MagNumTestCase::testAssignmentOperator()
{
	// given
	double expected = 2.56;
	MagNum given(expected);

	// when
	MagNum actual;
	actual = given;

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Assignment operator works wrong, should be 2.56", expected, actual.getDouble());
}

void MagNumTestCase::testAssignmentOperatorChaining()
{
	// given
	double expected = 2.56;
	MagNum given(expected);

	// when
	MagNum actual, b, c, d, e;
	actual = b = c = d = e = given;

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Assignment operator works wrong when chained, should be 2.56", expected, actual.getDouble());
}

void MagNumTestCase::testPlusEqualsOperator() {
	// given
	MagNum a = "5";
	MagNum b = "6.66";

	// when
	a += b;

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Adding operator works wrong, should be 11.66", 11.66, a.getDouble());
}

void MagNumTestCase::testMinusEqualsOperator() {
	// given
	MagNum a = "5";
	MagNum b = "6";

	// when
	b -= a;

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Subtracting operator works wrong, should be 1", 1, b.getInt());
}

void MagNumTestCase::testMulEqualsOperator() {
	// given
	MagNum a = "6";
	MagNum b = "1.11";

	// when
	a *= b;

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Multiplying operator works wrong, should be 6.66", 6.66, a.getDouble());
}

void MagNumTestCase::testDivEqualsOperator() {
	// given
	MagNum a = "1";
	MagNum b = "3";

	// when
	a /= b;

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Dividing operator works wrong, should be 0.333333333", 1/3.0, a.getDouble());
}

void MagNumTestCase::testMinusOperatorWhenPositive() {
	// given
	MagNum a = 4;

	// when
	MagNum result = -a;
	int actual = result.getInt();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Unary minus operator works wrong, should be -4", -4, actual);
}

void MagNumTestCase::testMinusOperatorWhenNegative() {
	// given
	MagNum a = -4;

	// when
	MagNum result = -a;

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Unary minus operator works wrong, should be 4", 4, result.getInt());
}

void MagNumTestCase::testMinusOperatorWhenZero() {
	// given
	MagNum a = 0;

	// when
	MagNum result = -a;
	bool comparisonResult = (result == a);
	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Unary minus operator works wrong, should be 0", 0, result.getInt());
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Unary minus operator works wrong, should be true", true, comparisonResult);
}

void MagNumTestCase::testMinusOperatorWhenNegative();
void MagNumTestCase::testMinusOperatorWhenZero();


void MagNumTestCase::testEqualsOperatorTrue() {
	// given
	MagNum a = 5;
	MagNum b = "5";

	// when
	bool result = (a==b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Equals operator works wrong, should be true", true, result);
}

void MagNumTestCase::testEqualsOperatorFalse() {
	// given
	MagNum a = 6;
	MagNum b = "5";

	// when
	bool result = (a==b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Equals operator works wrong, should be false", false, result);
}

void MagNumTestCase::testNotEqualsOperatorTrue() {
	// given
	MagNum a = 5;
	MagNum b = "6";

	// when
	bool result = (a!=b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("NotEquals operator works wrong, should be true", true, result);
}

void MagNumTestCase::testNotEqualsOperatorFalse() {
	// given
	MagNum a = 6;
	MagNum b = "6";

	// when
	bool result = (a!=b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("NotEquals operator works wrong, should be false", false, result);
}

void MagNumTestCase::testGreaterEqualsOperatorTrueWhenEqual() {
	// given
	MagNum a = 6;
	MagNum b = "6";

	// when
	bool result = (a>=b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("GreaterEquals operator works wrong, should be true", true, result);
}


void MagNumTestCase::testGreaterEqualsOperatorTrueWhenGreater() {
	// given
	MagNum a = 8;
	MagNum b = "6";

	// when
	bool result = (a>=b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("GreaterEquals operator works wrong, should be true", true, result);
}

void MagNumTestCase::testGreaterEqualsOperatorFalse() {
	// given
	MagNum a = 4;
	MagNum b = "6";

	// when
	bool result = (a>=b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("GreaterEquals operator works wrong, should be false", false, result);
}

void MagNumTestCase::testLessEqualsOperatorTrueWhenLess() {
	// given
	MagNum a = 4;
	MagNum b = "6";

	// when
	bool result = (a<=b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("LessEquals operator works wrong, should be true", true, result);
}

void MagNumTestCase::testLessEqualsOperatorTrueWhenEqual() {
	// given
	MagNum a = 4;
	MagNum b = "4";

	// when
	bool result = (a<=b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("LessEquals operator works wrong, should be true", true, result);
}

void MagNumTestCase::testLessEqualsOperatorFalse() {
	// given
	MagNum a = 8;
	MagNum b = "4";

	// when
	bool result = (a<=b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("LessEquals operator works wrong, should be false", false, result);
}

void MagNumTestCase::testGreaterOperatorTrue() {
	// given
	MagNum a = 18;
	MagNum b = "11";

	// when
	bool result = (a>b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Greater operator works wrong, should be true", true, result);
}

void MagNumTestCase::testGreaterOperatorFalseWhenEqual() {
	// given
	MagNum a = 11;
	MagNum b = "11";

	// when
	bool result = (a>b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Greater operator works wrong, should be false", false, result);
}

void MagNumTestCase::testGreaterOperatorFalseWhenLess() {
	// given
	MagNum a = 1;
	MagNum b = "11";

	// when
	bool result = (a>b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Greater operator works wrong, should be false", false, result);
}

void MagNumTestCase::testLessOperatorTrue() {
	// given
	MagNum a = 8;
	MagNum b = "11";

	// when
	bool result = (a<b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Less operator works wrong, should be true", true, result);
}

void MagNumTestCase::testLessOperatorFalseWhenEqual() {
	// given
	MagNum a = 8;
	MagNum b = "8";

	// when
	bool result = (a<b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Less operator works wrong, should be false", false, result);
}

void MagNumTestCase::testLessOperatorFalseWhenGreater() {
	// given
	MagNum a = 8;
	MagNum b = "4";

	// when
	bool result = (a<b);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("Less operator works wrong, should be false", false, result);
}

void MagNumTestCase::testChangeSignWhenPositive() {
	// given
	MagNum a = 4;

	// when
	a.changeSign();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("changeSign() works wrong, should be -4", -4, a.getInt());
}

void MagNumTestCase::testChangeSignWhenNegative() {
	// given
	MagNum a = -4;

	// when
	a.changeSign();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("changeSign() works wrong, should be 4", 4, a.getInt());
}

void MagNumTestCase::testChangeSignWhenZero() {
	// given
	MagNum a = 0;

	// when
	a.changeSign();
	MagNum b = a;
	b.changeSign();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("changeSign() works wrong, should be 0", 0, a.getInt());
	CPPUNIT_ASSERT_MESSAGE("changeSign() works wrong, should be true", a==b);
}

void MagNumTestCase::testChangeSignTwoTimes() {
	// given
	MagNum a = 5;
	MagNum b = a;

	// when
	b.changeSign().changeSign();

	// then
	CPPUNIT_ASSERT_MESSAGE("changeSign() works wrong, should be true", a==b);
}

void MagNumTestCase::testAbsWhenPositive() {
	// given
	MagNum a = 4;

	// when
	a.abs();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("changeSign() works wrong, should be 4", 4, a.getInt());
}

void MagNumTestCase::testAbsWhenNegative() {
	// given
	MagNum a = -4;

	// when
	a.abs();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("changeSign() works wrong, should be 4", 4, a.getInt());
}

void MagNumTestCase::testAbsWhenZero() {
	// given
	MagNum a = 0;

	// when
	a.abs();
	MagNum b = a;
	b.abs();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("abs() works wrong, should be 0", 0, a.getInt());
	CPPUNIT_ASSERT_MESSAGE("abs() works wrong, should be true", a==b);
}

void MagNumTestCase::testGetAbsWhenPositive() {
	// given
	MagNum a = 4;

	// when
	MagNum b = a.getAbs();
	b.abs();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("getAbs() works wrong, should be 4", 4, b.getInt());
	CPPUNIT_ASSERT_MESSAGE("getAbs() works wrong, should be true", a == a);
}

void MagNumTestCase::testGetAbsWhenNegative() {
	// given
	MagNum a = -4;

	// when
	MagNum b = a.getAbs();
	b.abs();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("getAbs() works wrong, should be 4", 4, b.getInt());
	CPPUNIT_ASSERT_MESSAGE("getAbs() works wrong, should be true", a != b);
}

void MagNumTestCase::testGetAbsWhenZero() {
	// given
	MagNum a = 0;

	// when
	a.abs();
	MagNum b = a.getAbs();
	b.abs();

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("getAbs() works wrong, should be 0", 0, b.getInt());
}

void MagNumTestCase::testPowWhenZero() {
	// given
	MagNum a = 0;

	// when
	a.pow(MagNum::TWO);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("pow() works wrong when number is 0, should be 0", 0, a.getInt());
}

void MagNumTestCase::testPowWhenArgIsZero() {
	// given
	MagNum a = 3;

	// when
	a.pow(MagNum::ZERO);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("pow() works wrong when arg is 0, should be 1", 1, a.getInt());
}

void MagNumTestCase::testPow() {
	// given
	MagNum a = 3;

	// when
	a.pow(MagNum::TWO);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("pow() works wrong, should be 9", 9, a.getInt());
}

void MagNumTestCase::testGetPowWhenZero() {
	// given
	MagNum a = 0;

	// when
	MagNum b = a.getPow(MagNum::TWO);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("pow() works wrong, a should not change", a.getInt(), a.getInt());
	CPPUNIT_ASSERT_EQUAL_MESSAGE("pow() works wrong when number is 0, should be 0", 0, b.getInt());
}

void MagNumTestCase::testGetPowWhenArgIsZero() {
	// given
	MagNum a = 3;

	// when
	MagNum b = a.getPow(MagNum::ZERO);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("pow() works wrong, a should not change", a.getInt(), a.getInt());
	CPPUNIT_ASSERT_EQUAL_MESSAGE("pow() works wrong when arg is 0, should be 1", 1, b.getInt());
}

void MagNumTestCase::testGetPow() {
	// given
	MagNum a = 3;

	// when
	MagNum b = a.getPow(MagNum::TWO);

	// then
	CPPUNIT_ASSERT_EQUAL_MESSAGE("pow() works wrong, a should not change", a.getInt(), a.getInt());
	CPPUNIT_ASSERT_EQUAL_MESSAGE("pow() works wrong, should be 9", 9, b.getInt());
}

void MagNumTestCase::testRange() {
	mpfr_set_default_prec(80);

	MagNum a = 1;
	MagNum b = "0.1";
	MagNum result = 1, resultPrev = 0;
	int count = 0;


	while(1) {
		count++;

		result = a;
		CPPUNIT_ASSERT_MESSAGE("blad", result > resultPrev);
		resultPrev = result;

		mpfr_printf ("%d: %.100Rf\n", 0, *result.getMpfr());

		result += b;
		CPPUNIT_ASSERT_MESSAGE("blad", result > resultPrev);
		resultPrev = result;

		mpfr_printf ("%d: %.100Rf\n", 0, *result.getMpfr());

		a *= 10;
		b /= 10;
	}
}

void MagNumTestCase::testFactorialDivision() {
	mpfr_set_default_prec(300);

	MagNum result = 1;
	result /= 6;
	mpfr_printf ("\n\n%d: %.100Rf\n", 0, *result.getMpfr());


	for(int i = 2; i < 5001; i++) {

		result /= i;
//		mpfr_printf ("%d: %.1000Rf\n", i, *result.getMpfr());

	}

	result = result.sqrt();
	mpfr_printf ("%d: %.1000Rf\n", 51, *result.getMpfr());

	result = result.sqrt();
	mpfr_printf ("%d: %.1000Rf\n", 52, *result.getMpfr());

	result = result.pow(4);
	mpfr_printf ("%d: %.1000Rf\n", 51, *result.getMpfr());


	for(int i = 2; i < 5001; i++) {

		result *= i;
//		mpfr_printf ("%d: %.1000Rf\n", i, *result.getMpfr());

	}
	mpfr_printf ("%d: %.100Rf\n", 0, *result.getMpfr());
}


double double_b(const double& a, const int& k) ;
double double_b_prime(const double& a, const int& k) ;
MagNum b(const MagNum& a, const MagNum& k);
MagNum b_prime(const MagNum& a, const MagNum& k);
void b_both(const MagNum& a, const MagNum& k, MagNum* b, MagNum* b_prime);
void double_Feigenbaum();
void Feigenbaum();
void FeigenbaumNoRecursion();

void MagNumTestCase::testB_both() {
	// given
	MagNum a = 3;
	MagNum k1 = 0;
	MagNum k2 = 1;
	MagNum k3 = 2;
	MagNum k4 = 3;
	MagNum result_b = 0;
	MagNum result_b_prime = 0;

	// when
	b_both(a, k1, &result_b, &result_b_prime);
	// then
	CPPUNIT_ASSERT_MESSAGE("should return zero when k = 0", result_b == b(a, k1));
	CPPUNIT_ASSERT_MESSAGE("should return zero when k = 0", result_b_prime == b_prime(a, k1));

	// when
	b_both(a, k2, &result_b, &result_b_prime);
	// then
	CPPUNIT_ASSERT_MESSAGE("wrong b_prime for k2", result_b_prime == b_prime(a, k2));
	CPPUNIT_ASSERT_MESSAGE("wrong b for k2", result_b == b(a, k2));

	// when
	b_both(a, k3, &result_b, &result_b_prime);
	// then
	CPPUNIT_ASSERT_MESSAGE("wrong b_prime for k3", result_b_prime == b_prime(a, k3));
	CPPUNIT_ASSERT_MESSAGE("wrong b for k3", result_b == b(a, k3));

	// when
	b_both(a, k4, &result_b, &result_b_prime);
	// then
	CPPUNIT_ASSERT_MESSAGE("wrong b_prime for k4", result_b_prime == b_prime(a, k4));
	CPPUNIT_ASSERT_MESSAGE("wrong b for k4", result_b == b(a, k4));

}
void MagNumTestCase::testB() {
	// given
	double a = 3;
	double k1 = 0;
	double k2 = 1;
	double k3 = 2;
	double k4 = 3;
	double expected2 = 3;
	double expected3 = -6;
	double expected4 = -33;
	// when
	double result = double_b(a,k1);
	// then
	CPPUNIT_ASSERT_MESSAGE("should return zero when k = 0", result == 0.0);

	// when
	result = double_b(a, k2);
	// then
	CPPUNIT_ASSERT_MESSAGE("should return 3 when k = 1", result == expected2);

	// when
	result = double_b(a, k3);
	// then
	CPPUNIT_ASSERT_MESSAGE("should return -15 when k = 2", result == expected3);

	// when
	result = double_b(a, k4);
	// then
	CPPUNIT_ASSERT_MESSAGE("should return -33 when k = 2", result == expected4);
}
//void MagNumTestCase::testB() {
//	// given
//	MagNum a = 3;
//	MagNum k1 = 0;
//	MagNum k2 = 1;
//	MagNum k3 = 2;
//	MagNum k4 = 3;
//	MagNum expected2 = 3;
//	MagNum expected3 = -6;
//	MagNum expected4 = -33;
//	// when
//	MagNum result = b(a,k1);
//	// then
//	CPPUNIT_ASSERT_MESSAGE("should return zero when k = 0", result == MagNum::ZERO);
//
//	// when
//	result = b(a, k2);
//	// then
//	CPPUNIT_ASSERT_MESSAGE("should return 3 when k = 1", result == expected2);
//
//	// when
//	result = b(a, k3);
//	// then
//	CPPUNIT_ASSERT_MESSAGE("should return -15 when k = 2", result == expected3);
//
//	// when
//	result = b(a, k4);
//	// then
//	CPPUNIT_ASSERT_MESSAGE("should return -33 when k = 2", result == expected4);
//}

void MagNumTestCase::testBprime() {
	// given
	double a = 3;
	double k1 = 0;
	double k2 = 1;
	double k3 = 2;
	double k4 = 3;
	double expected2 = 1;
	double expected3 = -5;
	double expected4 = -59;
	// when
	double result = double_b_prime(a,k1);
	// then
	CPPUNIT_ASSERT_MESSAGE("should return zero when k = 0", result == 0.0);

	// when
	result = double_b_prime(a, k2);
	// then
	CPPUNIT_ASSERT_MESSAGE("should return 1 when k = 1", result == expected2);

	// when
	result = double_b_prime(a, k3);
	// then
	CPPUNIT_ASSERT_MESSAGE("should return -5 when k = 2", result == expected3);

	// when
	result = double_b_prime(a, k4);
	// then
	CPPUNIT_ASSERT_MESSAGE("should return -59 when k = 2", result == expected4);
}

//void MagNumTestCase::testBprime() {
//	// given
//	MagNum a = 3;
//	MagNum k1 = 0;
//	MagNum k2 = 1;
//	MagNum k3 = 2;
//	MagNum k4 = 3;
//	MagNum expected2 = 1;
//	MagNum expected3 = -5;
//	MagNum expected4 = -59;
//	// when
//	MagNum result = b_prime(a,k1);
//	// then
//	CPPUNIT_ASSERT_MESSAGE("should return zero when k = 0", result == MagNum::ZERO);
//
//	// when
//	result = b_prime(a, k2);
//	// then
//	CPPUNIT_ASSERT_MESSAGE("should return 1 when k = 1", result == expected2);
//
//	// when
//	result = b_prime(a, k3);
//	// then
//	CPPUNIT_ASSERT_MESSAGE("should return -5 when k = 2", result == expected3);
//
//	// when
//	result = b_prime(a, k4);
//	// then
//	CPPUNIT_ASSERT_MESSAGE("should return -59 when k = 2", result == expected4);
//}

void MagNumTestCase::testFaigenbaumConstant() {
//	double_Feigenbaum();
	Feigenbaum();
}

void MagNumTestCase::testFaigenbaumConstantNoRecursion() {
	FeigenbaumNoRecursion();
}

//
//MagNum b(const MagNum& a, const MagNum& k) {
//	if(k==MagNum::ZERO)
//		return MagNum::ZERO;
////	MagNum deeper = b(a, k-MagNum::ONE);
////	MagNum deeperSqr = deeper.getPow(MagNum::TWO);
////	MagNum result = a - deeper.getPow(MagNum::TWO);
////    mpfr_printf("a=%.10Rf\tk=%.10Rf\n", *a.getMpfr(), *k.getMpfr());
////    mpfr_printf("b=%.10Rf\tb^2=%.10Rf\n", *deeper.getMpfr(), *deeperSqr.getMpfr());
////    mpfr_printf("result=%.10Rf\n", *result.getMpfr(), *deeperSqr.getMpfr());
////	return result;
//	return a - b(a, k-MagNum::ONE).getPow(MagNum::TWO);
//}
//
//MagNum b_prime(const MagNum& a, const MagNum& k) {
//	if(k==MagNum::ZERO)
//		return MagNum::ZERO;
//	return MagNum::ONE - MagNum::TWO*b_prime(a, k-MagNum::ONE)*b(a, k-MagNum::ONE);
//}

double double_b(const double &a, const int &k) {

    double x = 0;
	for(int i = 0; i < k; i++ ) {
		x = a - x * x;
	}
	return x;
}

double double_b_prime(const double& a, const int& k) {
	double x = 0;
	double y = 0;
	for(int i = 0; i < k; i++ ) {
		y = 1 - 2 * y * x;
		x = a - x * x;
	}
	return y;
}

MagNum b(const MagNum& a, const MagNum& k) {

    MagNum x = 0;
	for(int i = 0; i < k.getInt(); i++ ) {
		x = a - x * x;
	}
	return x;
}

MagNum b_prime(const MagNum& a, const MagNum& k) {
	MagNum x = 0;
	MagNum y = 0;
	for(int i = 0; i < k.getInt(); i++ ) {
		y = MagNum::ONE - MagNum::TWO * y * x;
		x = a - x * x;
	}
	return y;
}

void b_both(const MagNum& a, const MagNum& k, MagNum* b, MagNum* b_prime) {
	MagNum x = 0;
	MagNum y = 0;
	int k_int = k.getInt();
	for(int i = 0; i < k_int; i++ ) {
		y = MagNum::ONE - MagNum::TWO * y * x;
		x = a - x * x;
	}
	*b = x;
	*b_prime = y;
}

void Feigenbaum() {
	mpfr_printf("Feigenbaum constant calculation:\n");

	mpfr_set_default_prec(100);

	int maxIt = 35;
	int maxItJ = 1;
	MagNum ai_1 = 1;
	MagNum ai_2 = 0;
	MagNum di_1 = 3.2;
	MagNum two = 2;
	MagNum b = 0;
	MagNum b_prime = 0;
	mpfr_printf("\ni\tdi\n");
	for(int i = 2; i <= maxIt; i++) {
	    MagNum ai = ai_1 + (ai_1 - ai_2) / di_1;
	    MagNum twoPowI = two.getPow(MagNum(i));
	    for(int j = 0; j <= maxItJ; j++) {
	    	b_both(ai, twoPowI, &b, &b_prime);
	        ai = ai - b / b_prime;
		    mpfr_printf("\t\t%dai = %.100Rf\n", i, *ai.getMpfr());
	    }
	    MagNum di = (ai_1 - ai_2) / (ai - ai_1);
	    mpfr_printf("%d\t%.100Rf\n", i, *di.getMpfr());
	    di_1 = di;
	    ai_2 = ai_1;
	    ai_1 = ai;
	}

}

void double_Feigenbaum() {
	mpfr_printf("Feigenbaum constant calculation:\n");

//	mpfr_set_default_prec(500);

	int maxIt = 2;
	int maxItJ = 5;
	double ai_1 = 1;
	double ai_2 = 0;
	double di_1 = 3.2;
	mpfr_printf("\ni\tdi\n");
	for(int i = 2; i <= maxIt; i++) {
		double ai = ai_1 + (ai_1 - ai_2) / di_1;
	    for(int j = 0; j <= maxItJ; j++) {
	        ai = ai - double_b(ai, 2<<i) / double_b_prime(ai, 2<<i);
		    printf("\t\t%dai = %.100f\n", i, ai);
	    }
	    double di = (ai_1 - ai_2) / (ai - ai_1);
	    printf("%d\t%.100f\n", i, di);
	    di_1 = di;
	    ai_2 = ai_1;
	    ai_1 = ai;
	}

}

void FeigenbaumNoRecursion() {

	mpfr_set_default_prec(600);

	MagNum e = MagNum::exp(1);
    mpfr_printf("\ne = %.200Rf\n", *e.getMpfr());

	MagNum pi = MagNum::getPi();
    mpfr_printf("pi = %.200Rf\n", *pi.getMpfr());

    MagNum radians = 72;
    radians /= 180;
    radians *= pi;

    MagNum fDelta = e * pi * 13 / (MagNum::sin(radians) * 25);

    mpfr_printf("delta = %.200Rf\n", *fDelta.getMpfr());

}

double generateNumber(short* a) {
	double part = 0.5;
	double result = 0.0;

	for(int i = 2; i<32; i++) {
		if(rand()%2==1) {
			result += part;
			a[i] = 1;
		}
		else {
			a[i] = 0;
		}
		part /= 2.0;
	}
	return result;
}

double dec2bin(double dec, short *bin) {
	double part = 1.0;
	double result = 0.0;
	for(int i=1; i<32; i++) {
		if(dec > 1) {
			bin[i] = 1;
			result += part;
		} else {
			bin[i] = 0;
		}
		dec -= bin[i];
		dec *= 2.0;
		part /= 2.0;
	}
	return result;
}

double bin2dec(short *a) {
	double result = 0.0;
	double part = 2.0;

	for(int i=0; i<32; i++) {
		if(a[i]!=0) {
			result += part;
		}
		part /= 2.0;
	}
	return result;
}
void print(short* a) {
	for(int i=0; i<32; i++) {
		printf("%d", a[i]);
	}
}

double noise(short *a, int amount) {
	int noisator = 1;
	if(amount < 0) {
		noisator = 0;
		amount *= -1;
	}

	for(int i=0; i<amount; i++) {
		a[31-i] = noisator;
	}

	return bin2dec(a);
}

void MagNumTestCase::testConverting() {

	float a = 100000000000.0;
	float b = 0.00000000001;
	b += 0.00000000001;
	b += 0.00000000001;
	b += 0.00000000001;
	b += 0.00000000001;
	b += 0.00000000001;
	if(b > 0.00000000005) {
		b += a;
		b -= a;
		if(b == 0.0) {
			std::cerr << "BLAD";
		}
	}


//	short a[32] = {0};
//	short b[32] = {0};
//	srand(time(NULL));
//
//	double d = (double)(rand()%10000000000)/10000000000.0;
//	printf("a = %13.10f\n", d);
//	d = dec2bin(d, a);
//	printf("%13.10f : ", d);
//	print(a);
//	d = bin2dec(a);
//	printf(" : %13.10f\n", d);
//
//	d = generateNumber(b);
//	printf("b = %13.10f\n", d);
//	d = dec2bin(d, b);
//	printf("%13.10f : ", d);
//	print(b);
//	d = bin2dec(b);
//	printf(" : %13.10f\n", d);
}

void printPair(double da, double db, short* a, short* b) {
	printf("a = %13.10f, b = %13.10f, ", da, db);
	print(a);
	printf(" ");
	print(b);
	printf("\n");
}

int errorLength(short* a) {
	for(int i=0; i<32; i++) {
		if(a[i]>0)
			return 32-i;
	}
	return 0;
}

void MagNumTestCase::testBinaryAdding() {

	short a[32] = {0};
	short b[32] = {0};
	short result[32] = {0};

	for(int i=0; i<10000; i++) {
		double da = generateNumber(a);
		double db = generateNumber(b);
//		printPair(da, db, a, b);

		int noiseA = rand()%10+5;
		int noiseB = rand()%10+5;
		double nda = noise(a, noiseA);
		double ndb = noise(b, noiseB);
//		printPair(nda, ndb, a, b);

		double sum = nda+ndb;
		double error = da+db-sum;
		if(error < 0.0) error *= -1.0;
		dec2bin(error, result);
		int errorLen = errorLength(result);
//		printf("\n %2d, %2d, %12.10f %2d ", noiseA, noiseB, error, errorLen); print(result);
		CPPUNIT_ASSERT(errorLen <= (noiseA > noiseB ? noiseA : noiseB) + 1);

		noiseA *= -1;
		noiseB *= -1;
		nda = noise(a, noiseA);
		ndb = noise(b, noiseB);
//		printPair(nda, ndb, a, b);

		sum = nda+ndb;
		error = da+db-sum;
		if(error < 0.0) error *= -1.0;
		dec2bin(error, result);
		errorLen = errorLength(result);
//		printf("\n %2d, %2d, %12.10f %2d ", noiseA, noiseB, error, errorLen); print(result);
		CPPUNIT_ASSERT(errorLen <= (-noiseA > -noiseB ? -noiseA : -noiseB) + 1);
	}
}

void MagNumTestCase::testBinaryMultplying() {

	short a[32] = {0};
	short b[32] = {0};
	short result[32] = {0};

	for(int i=0; i<10000; i++) {
		double da = generateNumber(a);
		double db = generateNumber(b);
//		printPair(da, db, a, b);

		int noiseA = rand()%10+5;
		int noiseB = rand()%10+5;
		double nda = noise(a, noiseA);
		double ndb = noise(b, noiseB);
//		printPair(nda, ndb, a, b);

		double product = nda*ndb;
		double error = da*db-product;
		if(error < 0.0) error *= -1.0;
		dec2bin(error, result);
		int errorLen = errorLength(result);
//		printf("\n %2d, %2d, %12.10f %2d ", noiseA, noiseB, error, errorLen); print(result);
		CPPUNIT_ASSERT(errorLen <= (noiseA > noiseB ? noiseA : noiseB) + 1);

		noiseA *= -1;
		noiseB *= -1;
		nda = noise(a, noiseA);
		ndb = noise(b, noiseB);
//		printPair(nda, ndb, a, b);

		product = nda*ndb;
		error = da*db-product;
		if(error < 0.0) error *= -1.0;
		dec2bin(error, result);
		errorLen = errorLength(result);
//		printf("\n %2d, %2d, %12.10f %2d ", noiseA, noiseB, error, errorLen); print(result);
		CPPUNIT_ASSERT(errorLen <= (-noiseA > -noiseB ? -noiseA : -noiseB) + 1);
	}
}

void MagNumTestCase::testBinaryDividing() {

	short a[32] = {0};
	short b[32] = {0};
	short result[32] = {0};

	for(int i=0; i<1000; i++) {
		double da = generateNumber(a);
		double db = generateNumber(b);
//		printPair(da, db, a, b);

		int noiseA = rand()%10+5;
		int noiseB = rand()%10+5;
		double nda = noise(a, noiseA);
		double ndb = noise(b, noiseB);
//		printPair(nda, ndb, a, b);

		double fraction = nda/ndb;
		double error = da/db-fraction;
		if(fraction > 1.0) {
			fraction = 1 / fraction;
			error = db/da - fraction;
		}
		if(error < 0.0) error *= -1.0;
		dec2bin(error, result);
		int errorLen = errorLength(result);
		printf("\n %2d, %2d, %12.10f %2d ", noiseA, noiseB, error, errorLen); print(result);
		CPPUNIT_ASSERT(errorLen <= (noiseA > noiseB ? noiseA : noiseB) + 3);
	}
}
//
//void MagNumTestCase::testBinaryDividing() {
//
//	short a[32] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
//	short b[32] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
//	short result[32] = {0};
//
//	for(int i=0; i<10; i++) {
//		double da = generateNumber(a);
//		double db = generateNumber(b);
////		printPair(da, db, a, b);
//
//		int noiseA = rand()%10+5;
//		int noiseB = rand()%10+5;
//		double nda = noise(a, noiseA);
//		double ndb = noise(b, noiseB);
////		printPair(nda, ndb, a, b);
//
//		double fraction = nda/ndb;
//		double error = da/db-fraction;
//		if(error < 0.0) error *= -1.0;
//		dec2bin(error, result);
//		int errorLen = errorLength(result);
//		printf("\n %2d, %2d, %12.10f %2d ", noiseA, noiseB, error, errorLen); print(result);
////		CPPUNIT_ASSERT(errorLen <= (noiseA > noiseB ? noiseA : noiseB) + 2);
//	}
//}

void MagNumTestCase::testBinarySqrting() {

	short a[32] = {0};
	short b[32] = {0};
	short result[32] = {0};

	for(int i=0; i<10000; i++) {
		double da = generateNumber(a);
//		printPair(da, db, a, b);

		int noiseA = rand()%10+5;
		double nda = noise(a, noiseA);
//		printPair(nda, ndb, a, b);

		double root = sqrt(nda);
		double error = sqrt(da)-root;
		if(error < 0.0) error *= -1.0;
		dec2bin(error, result);
		int errorLen = errorLength(result);
		printf("\n %2d, %2d, %12.10f %2d ", noiseA, 0, error, errorLen); print(result);
		CPPUNIT_ASSERT(errorLen <= noiseA * 2 + 1);

		noiseA *= -1;
		nda = noise(a, noiseA);
//		printPair(nda, ndb, a, b);

		root = sqrt(nda);
		error = sqrt(da)-root;
		if(error < 0.0) error *= -1.0;
		dec2bin(error, result);
		errorLen = errorLength(result);
		printf("\n %2d, %2d, %12.10f %2d ", noiseA, 0, error, errorLen); print(result);
		if (errorLen > -noiseA * + 1) {
			printPair(da, 0, a, b);
			CPPUNIT_ASSERT(errorLen <= -noiseA + 3);
		}
	}
}

MagNum getRandomNoisedPair(MagNum& noiseUp, MagNum& noiseDown, int length, int noiseLength){

	MagNum firstExp = (rand()%length - length/2);
	MagNum random(0);
	noiseUp = 0;
	noiseDown = 0;
	MagNum part(MagNum::TWO.getPow(firstExp));
	for(int i=0; i<length; i++) {
		part /= 2;
		if((length-1-i < noiseLength)) {
			noiseUp += part;
		}
		else if(rand()%2 == 1 || i == 0) {
			random += part;
		}
	}
	noiseUp += random;
	noiseDown += random;
	MagNum noise = noiseUp-noiseDown;
	int noiseExp = noise.getMpfrExp();
	noiseUp.setCurrentPrecision(noiseExp);
	noiseDown.setCurrentPrecision(noiseExp);
	return noise;
}

//MagNum noiseIt(MagNum it, int length, int noiseLength, int noiseValue){
//
//	int firstExp = rand()%length - length/2;
//	MagNum random(0);
//	MagNum part(MagNum::TWO.pow(firstExp));
//	for(int i=0; i<length; i++) {
//		part /= 2;
//		if(rand()%2 == 1 || (noiseValue != 0 && length-i < noiseLength)) {
//			random += part;
//		}
//	}
//	return random;
//}

char* printBinary(char* result, const mp_limb_t limb) {
	for(int i=0; i<32; i++) {
		if((limb & (2 << (31-i))) > 0) {
			result[i] = '1';
		} else {
			result[i] = '0';
		}
	}
	return result;
}

void printBinary(char* result, const MagNum& magnum) {
	mp_limb_t *limbs = ((__mpfr_struct)(*(magnum.getMpfr()))[0])._mpfr_d;
	int length = (((__mpfr_struct)(*(magnum.getMpfr()))[0])._mpfr_prec + 31)/32;
	char limbString[32];

	char local[1000] = {0};
	for(int i=0; i<length; i++) {
		strcat(local, printBinary(limbString, limbs[length-i-1]));
	}
	printf("%s\n", local);
}

void MagNumTestCase::testMagNumSqrtingErrorMeasure() {

	gmp_randstate_t randState;
	gmp_randinit_default(randState);
	gmp_randseed_ui(randState, time(NULL));

	char output[1000] = {0};

	mpfr_set_default_prec(106);
	mpfr_t mpfr;
	mpfr_init(mpfr);
	printf("\n\ntestMagNumSqrtingErrorMeasure\n\n");
	mpfr_urandomb(mpfr, randState);
	MagNum a(&mpfr);
    mpfr_printf("a = %.200Rf\n", *a.getMpfr());

    mpfr_prec_round (mpfr, 80, mpfr_get_default_rounding_mode());

	MagNum a2(&mpfr);
    mpfr_printf("a2 = %.200Rf\n", *a2.getMpfr());


	MagNum b(0);
	MagNum c(0);
	MagNum part(1);
	for(int i=0; i<90; i++) {
		part /= 2;
		b += part;
	    if(i<85) c += part;
		mpfr_printf("b = %.200Rf\n", *b.getMpfr());
		mpfr_printf("c = %.200Rf\n", *c.getMpfr());
	}
	mpfr_printf("b = %.200Rf\n", *b.getMpfr());
	mpfr_printf("c = %.200Rf\n", *c.getMpfr());
	MagNum bSqrted = b.sqrt();
	mpfr_printf("      b = %+.200Rf\n", *b.getMpfr());
	mpfr_printf("bSqrted = %+.200Rf\n", *bSqrted.getMpfr());
	MagNum cSqrted = c.sqrt();
	mpfr_printf("      c = %+.200Rf\n", *c.getMpfr());
	mpfr_printf("cSqrted = %+.200Rf\n", *cSqrted.getMpfr());
	MagNum dif = cSqrted-bSqrted;
	mpfr_printf("    dif = %+.200Rf\n", *dif.getMpfr());

	for(int i=0; i<10; i++) {
		int noiseLength = rand()%20+5;
		MagNum noisedUp, noisedDown;
		MagNum diff = getRandomNoisedPair(noisedUp, noisedDown, 90, noiseLength);
		MagNum firstOne = MagNum::TWO.getPow(((__mpfr_struct)(*(diff.getMpfr()))[0])._mpfr_exp+((__mpfr_struct)(*(noisedUp.getMpfr()))[0])._mpfr_exp);
		mpfr_printf("\n");
		int expUp = ((__mpfr_struct)(*(noisedUp.getMpfr()))[0])._mpfr_exp;
		mpfr_printf("     exp = %d\n", expUp);
		mpfr_printf("      up = %+.200Rf\n", *noisedUp.getMpfr());
		printBinary(output, noisedUp);
		mpfr_printf("    down = %+.200Rf\n", *noisedDown.getMpfr());
		printBinary(output, noisedDown);
		mpfr_printf("    diff = %+.200Rf\n", *diff.getMpfr());
		mpfr_printf("     exp = %+.200Rf\n", *firstOne.getMpfr());
		mpfr_printf("  expExp = %d\n", ((__mpfr_struct)(*(firstOne.getMpfr()))[0])._mpfr_exp);
		printBinary(output, firstOne);
		MagNum sqrtUp = noisedUp.sqrt();
		MagNum sqrtDown = noisedDown.sqrt();
		MagNum diff2 = sqrtUp-sqrtDown;
		mpfr_printf("  sqrtUp = %+.200Rf\n", *noisedUp.getMpfr());
		printBinary(output, sqrtUp);
		mpfr_printf("sqrtDown = %+.200Rf\n", *noisedDown.getMpfr());
		printBinary(output, sqrtDown);
		mpfr_printf("   diff2 = %+.200Rf\n", *(diff2.getMpfr()));
//		printBinary(output, diff2);
		int howMany = 0;
		while(diff2 > diff) {
			diff *= 2;
			howMany++;
		}
		mpfr_printf(" howMany = %d\n", howMany);
		mpfr_printf("noiseLen = %d\n", noiseLength);
		int sqrtExp = ((__mpfr_struct)(*(sqrtUp.getMpfr()))[0])._mpfr_exp;
		mpfr_printf(" sqrtExp = %d\n", sqrtExp);
		mpfr_printf(" dif2Exp = %d\n", ((__mpfr_struct)(*(diff2.getMpfr()))[0])._mpfr_exp);
		printBinary(output, MagNum("-0.128"));
		mpfr_printf("-.128Exp = %d\n", ((__mpfr_struct)(*(MagNum("-0.128").getMpfr()))[0])._mpfr_exp);
	}
}
class klasa {

};

void MagNumTestCase::testOver100Listener() {
	MagNum number = 0.1;

	Over100ListenerImpl listener;

	number.addOver100Listener(&listener);

	for(int i=0; i<210; i++) {
		number += 0.5;
	}

	std::cout << number;
	printf("number is %s\n\n\n", number.getChars());


}

void MagNumTestCase::testMandelbrot() {

	mpfr_set_default_prec(MagNum::INITIAL_PRECISION);

	Mandelbrot<MagNum> mandelbrot;
	//	mandelbrot.run(-0.5, 0, 2);
//	mandelbrot.run(0.001643721971153, 0.822467633298876, 0.1);
//	mandelbrot.paint();
//	mandelbrot.run(0.001643721971153, 0.822467633298876, 0.05);
//	mandelbrot.paint();
//	mandelbrot.run(0.001643721971153, 0.822467633298876, 0.01);
//	mandelbrot.paint();

	printf("<html><style>tr { line-height: 3px; } td { width : 3px } body { background: black; }</style><body>");
//				   0.0000000000001
//	mandelbrot.run(0.001643721969153, 0.822467633298876, 0.0000000000001);
	mandelbrot.run();
	do {
		mandelbrot.paintConsole();
		mandelbrot.zoomIn();
		mandelbrot.run();
//		mandelbrot.paint();
	} while(std::cin.get() != 'q');

	printf("</body></html>");
}

void MagNumTestCase::testAddingError() {

	printf("testAddingError\n");

	int length = 50;
	int noiseLength = 10;
	MagNum noiseUpA, noiseDownA, noiseA;
	MagNum noiseUpB, noiseDownB, noiseB;
	int i=0;

	while(i++ < 100000) {
		noiseA = getRandomNoisedPair(noiseUpA, noiseDownA, length, noiseLength);

//		noiseUpA.print();
//		noiseDownA.print();
//		noiseA.print();
//		int noiseAExp = noiseA.getMpfrExp();
//		MagNum::TWO.getPow(noiseAExp).print();

		noiseB = getRandomNoisedPair(noiseUpB, noiseDownB, length, noiseLength);
//		noiseUpB.print();
//		noiseDownB.print();
//		noiseB.print();
//		int noiseBExp = noiseB.getMpfrExp();
//		MagNum::TWO.getPow(noiseBExp).print();

		MagNum sumDown = noiseDownA + noiseDownB;
		MagNum sumUp = noiseUpA + noiseUpB;
		MagNum noiseResult = sumUp - sumDown;

		MagNum maxNoise = MagNum::TWO.getPow(sumUp.getCurrentPrecision());
		maxNoise.print();
		noiseResult.print();

		CPPUNIT_ASSERT(maxNoise >= noiseResult);
	}
}

void MagNumTestCase::testSubtractingError() {

	printf("testSubtractingError\n");

	int length = 50;
	int noiseLength = 10;
	MagNum noiseUpA, noiseDownA, noiseA;
	MagNum noiseUpB, noiseDownB, noiseB;
	int i=0;

	while(i++ < 10000) {
		noiseA = getRandomNoisedPair(noiseUpA, noiseDownA, length, noiseLength);

//		noiseUpA.print();
//		noiseDownA.print();
//		noiseA.print();
//		int noiseAExp = noiseA.getMpfrExp();
//		MagNum::TWO.getPow(noiseAExp).print();

		noiseB = getRandomNoisedPair(noiseUpB, noiseDownB, length, noiseLength);
//		noiseUpB.print();
//		noiseDownB.print();
//		noiseB.print();
//		int noiseBExp = noiseB.getMpfrExp();
//		MagNum::TWO.getPow(noiseBExp).print();

		MagNum differenceDown = noiseDownA - noiseDownB;
		MagNum differenceUp = noiseUpA - noiseDownB;
		MagNum noiseResult = differenceUp - differenceDown;

		MagNum maxNoise = MagNum::TWO.getPow(differenceUp.getCurrentPrecision());
		maxNoise.print();
		noiseResult.print();

		CPPUNIT_ASSERT(maxNoise >= noiseResult);
	}
}

void MagNumTestCase::testMultiyplyingError() {

	printf("testMultiplyingError\n");

	int length = 50;
	int noiseLength = 10;
	MagNum noiseUpA, noiseDownA, noiseA;
	MagNum noiseUpB, noiseDownB, noiseB;
	int i=0;

	while(i++ < 100000) {
		noiseA = getRandomNoisedPair(noiseUpA, noiseDownA, length, noiseLength);

		printf("\n");
		printf("%6d %6d ", noiseUpA.getMpfrExp(), noiseUpA.getCurrentPrecision()); noiseUpA.print();
		printf("%6d %6d ", noiseDownA.getMpfrExp(), noiseDownA.getCurrentPrecision()); noiseDownA.print();
		noiseA.print();
		int noiseAExp = noiseA.getMpfrExp();
		MagNum::TWO.getPow(noiseAExp).print();

		noiseB = getRandomNoisedPair(noiseUpB, noiseDownB, length, noiseLength);
		printf("%6d %6d ", noiseUpB.getMpfrExp(), noiseUpB.getCurrentPrecision()); noiseUpB.print();
		printf("%6d %6d ", noiseDownB.getMpfrExp(), noiseDownB.getCurrentPrecision()); noiseDownB.print();
		noiseB.print();
		int noiseBExp = noiseB.getMpfrExp();
		MagNum::TWO.getPow(noiseBExp).print();

		MagNum productDown = noiseDownA * noiseDownB;
		MagNum productUp = noiseUpA * noiseUpB;
		printf("%6d %6d ", productDown.getMpfrExp(), productDown.getCurrentPrecision()); productDown.print();
		printf("%6d %6d ", productUp.getMpfrExp(), productUp.getCurrentPrecision()); productUp.print();
		MagNum noiseResult = productUp - productDown;

		MagNum maxNoise = MagNum::TWO.getPow(productUp.getCurrentPrecision());
		maxNoise.print();
		noiseResult.print();

		CPPUNIT_ASSERT(maxNoise >= noiseResult);
	}
}

void MagNumTestCase::testDividingError() {

	printf("testDividingError\n");

	int length = 50;
	int noiseLength = 10;
	MagNum noiseUpA, noiseDownA, noiseA;
	MagNum noiseUpB, noiseDownB, noiseB;
	int i=0;

	while(i++ < 1000000) {
		noiseA = getRandomNoisedPair(noiseUpA, noiseDownA, length, noiseLength);

		printf("\n");
		printf("%6d %6d ", noiseUpA.getMpfrExp(), noiseUpA.getCurrentPrecision()); noiseUpA.print();
		printf("%6d %6d ", noiseDownA.getMpfrExp(), noiseDownA.getCurrentPrecision()); noiseDownA.print();
		noiseA.print();
		int noiseAExp = noiseA.getMpfrExp();
		MagNum::TWO.getPow(noiseAExp).print();

		noiseB = getRandomNoisedPair(noiseUpB, noiseDownB, length, noiseLength);
		printf("%6d %6d ", noiseUpB.getMpfrExp(), noiseUpB.getCurrentPrecision()); noiseUpB.print();
		printf("%6d %6d ", noiseDownB.getMpfrExp(), noiseDownB.getCurrentPrecision()); noiseDownB.print();
		noiseB.print();
		int noiseBExp = noiseB.getMpfrExp();
		MagNum::TWO.getPow(noiseBExp).print();

		MagNum fractionDown = noiseDownA / noiseDownB;
		MagNum fractionUp = noiseUpA / noiseUpB;
		printf("%6d %6d ", fractionDown.getMpfrExp(), fractionDown.getCurrentPrecision()); fractionDown.print();
		printf("%6d %6d ", fractionUp.getMpfrExp(), fractionUp.getCurrentPrecision()); fractionUp.print();
		MagNum noiseResult = fractionUp - fractionDown;

		MagNum maxNoise = MagNum::TWO.getPow(fractionUp.getCurrentPrecision());
		maxNoise.print();
		noiseResult.print();

		CPPUNIT_ASSERT(maxNoise.getAbs() >= noiseResult.getAbs());
	}
}
